package com.example.demo.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.common.entity.pojo.BaseEntityPoJo;
import com.example.demo.common.listener.ImportListener;
import com.example.demo.common.service.BaseService;
import com.example.demo.common.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

import static org.apache.poi.ss.usermodel.BorderStyle.THIN;

/**
 * Excel工具.
 *
 * @author Mei Ruoxiao
 * @since 2020/8/25
 */
@Slf4j
public class ExcelUtil {

    /**
     * 导出数据
     *
     * @param list  集合
     * @param name  文件名
     * @param clazz 反射
     */
    public static <R extends BaseEntityPoJo, T extends BaseEntityPoJo> void writeWithHead(
            HttpServletResponse response, List<T> list, String name, Class<R> clazz) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        //编码，防止中文乱码
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(name, "utf-8");
        response.setHeader("Content-disposition",
                "attachment;filename=" + fileName + ExcelTypeEnum.XLSX.getValue());
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());


        // 这里，需要指定写用哪个class去写，然后写到第一个sheet，名字为模板，然后文件流会自动关闭
        // 如果这里想使用03，则传入excelType参数即可
        EasyExcel.write(response.getOutputStream(), clazz)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(getHorizontalCellStyleStrategy())
                .sheet("sheet1")
                .doWrite(list);
        response.flushBuffer();
    }

    /**
     * 导入数据
     *
     * @param file   文件
     * @param invoke invoke
     * @param clazz  反射
     * @throws Exception 异常
     */
    public static <T extends BaseService, R extends BaseEntityPoJo> List<R> readWithHead(
            MultipartFile file, final T invoke, Class<R> clazz) throws Exception {
        log.info("readWithHead");
        InputStream inputStream = file.getInputStream();
        // 这里需要指定读用哪个class去读，然后读取第一个sheet
        List<R> lists = EasyExcel.read(inputStream)
                // 注册监听器，可以在这里校验字段
                .registerReadListener(new ImportListener(invoke))
                .head(clazz)
                // 设置sheet,默认读取第一个
                .sheet()
                // 设置标题所在行数
                .headRowNumber(1)
                .doReadSync();
        return lists;
    }

    /**
     * 用于设置excel导出时的样式
     */
    public static HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() {
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为白色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
        // 字体大小
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 11);
        headWriteFont.setBold(false);
        headWriteCellStyle.setWriteFont(headWriteFont);

        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setBorderLeft(THIN);
        contentWriteCellStyle.setBorderTop(THIN);
        contentWriteCellStyle.setBorderRight(THIN);
        contentWriteCellStyle.setBorderBottom(THIN);

        // 这个策略 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
}
